package com.hc.java.lock;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author cdhuangchao3
 * @date 2023/12/3 5:07 PM
 */
public class ReentrantLockTest {
    // 锁对象
    static ReentrantLock lock = new ReentrantLock();
    // 条件1
    static Condition c1 = lock.newCondition();
    // 条件2
    static Condition c2 = lock.newCondition();


    public static void main(String[] args) throws InterruptedException {

        // 可打断
//        lockInterrupt();
        // 可超时
//        timeOutLock();
        // 多条件变量
        conditionTest();
    }

    private static void conditionTest() {
        new Thread(() -> {
            System.out.println("线程1进入");
            lock.lock();
            try {
                System.out.println("线程1await");
                c1.await();
                System.out.println(Thread.currentThread().getName() + ",acquire lock...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "t1").start();
        new Thread(() -> {
            System.out.println("线程2进入");
            lock.lock();
            try {
                System.out.println("线程2 await");
                c2.await();
                System.out.println(Thread.currentThread().getName() + ",acquire lock...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "t2").start();
        new Thread(() -> {
            System.out.println("线程3进入");
            lock.lock();
            try {
                // 唤醒c1条件的线程
                c1.signal();
                // 换新c2条件的线程
                c2.signal();
                System.out.println(Thread.currentThread().getName() + ",acquire lock...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }, "t3").start();
    }

    private static void timeOutLock() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            // 尝试获取锁，如果获取锁成功，返回true，否则返回false
            System.out.println("线程1进入");
            try {
                if (!lock.tryLock(2, TimeUnit.SECONDS)) {
                    System.out.println("t1-获取锁失败");
                    return;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("t1-线程-获得了锁");
            lock.unlock();
        }, "t1");

        lock.lock();
        try {
            System.out.println("主线程获得了锁");
            t1.start();
            Thread.sleep(3000);
        } finally {
            lock.unlock();
        }
    }

    private static void lockInterrupt() throws InterruptedException {
        Thread t1 = new Thread(() -> {
            try {
                // 开启可中断的锁
                lock.lockInterruptibly();
            } catch (InterruptedException e) {
                e.printStackTrace();
                System.out.println("等待的过程中被打断");
                return;
            }
            System.out.println("t1-线程-获得了锁");
            lock.unlock();
        }, "t1");
        lock.lock();
        System.out.println("主线程获得了锁");
        t1.start();
        try {
            Thread.sleep(1000);
            t1.interrupt();
            System.out.println("执行打断");
        } finally {
            lock.unlock();
        }
    }
}
